#include "xmethod.h"
#include <algorithm>

void CXMethod::firstMUpdate(list<w>::iterator it)
{
	list<w>::iterator it2 = it;
	++it2;

	m_max_tg = fabs(it2->y - it->y)/(it2->x - it->x);

	m_m = (m_max_tg > 0.01) ? m_r * m_max_tg : 1.0;

	return ;
}

bool CXMethod::MUpdate(list<w>::iterator it)
{
	bool flag = true;
	list<w>::iterator it2 = it;
	++it2;
	double temp1 = fabs(it->y - it2->y)/(it2->x - it->x);
	double temp2 = fabs((++it)->y - (++it2)->y)/(it2->x - it->x);
	temp1 = (temp1 < temp2) ? temp2 : temp1;
	m_max_tg = ( (flag = (temp1 < m_max_tg)) ) ? m_max_tg : temp1;
	m_m = (m_max_tg > 0.01)? (m_r * m_max_tg) : 1.0;

	return !flag;
}

list<w>::iterator CXMethod::MaxR()
{// поиск максимальной характеристики, с пересчитыванием характеристик

	list<w>::iterator i = m_W.begin(), end = m_W.end(), IterMax = i;
	end--;
	double temp_R = R(IterMax), temp;
	i++;
	for (; i!=end; i++)
	{
		if (temp_R < ( temp = R(i)))
		{
			IterMax = i;
			temp_R = temp;
		}
	}

	return IterMax;
}


static bool CompareR(const w& x1, const w& x2)
{
	return x1.R < x2.R;
}

void CXMethod::calculate(   CFunc * f, double a, double b,
	int steps, double epsilon,
	double m, double r, bool isAdaptiveConstLip,
	double &realepsilon, int &realsteps,
	double &XMin, double &YMin, list<CMyPoint> &Labels)
{
	//инициализация begin

	bool flagUpdateM = false;
	Labels.clear();
	m_W.clear();
	m_f = f;
	m_m = m;
	m_r = r;
	w temp;
	int i = 0;
	list<w>::iterator MaxRIter, MinIter, IterTemp;

	{
		realepsilon = b - a;
		temp.x = a;
		temp.y = m_f->operator ()(a);
		m_W.push_back(temp);
		Labels.push_back(CMyPoint( temp.x, temp.y));
		temp.x = b;
		temp.y = m_f->operator ()(b);
		m_W.push_back(temp);
		Labels.push_back(CMyPoint( temp.x, temp.y));

		MaxRIter = MinIter = m_W.begin();
		if (MinIter->y > (++(IterTemp = MaxRIter))->y)
			MinIter = IterTemp;

		if (isAdaptiveConstLip)
		{
			firstMUpdate(MaxRIter);
		}
	}

	//основной алгоритм
	for ( i = 2; i < steps && epsilon < realepsilon; i++)
	{
		if (isAdaptiveConstLip && flagUpdateM)
		{
			MaxRIter = MaxR();
		}
		else
		{
			MaxRIter = max_element(m_W.begin(), m_W.end(), CompareR);
		}
		realepsilon = (++(IterTemp = MaxRIter))->x - MaxRIter->x;

		//add new experiment
		temp.x = d(MaxRIter);
		temp.y = m_f->operator ()(temp.x);
		Labels.push_back(CMyPoint(temp.x,temp.y)); // log
		IterTemp = m_W.insert(++(IterTemp = MaxRIter), temp); // safe threaded???
		MaxRIter->R = R(MaxRIter);
		IterTemp->R = R(IterTemp);
		if (MinIter->y > IterTemp->y)
			MinIter = IterTemp;
		
		if (isAdaptiveConstLip)
			flagUpdateM = MUpdate(MaxRIter);
	}


	//завершение
	realsteps = i;
	XMin = MinIter->x;
	YMin = MinIter->y;
	m_W.clear();
	m_f = 0;
	return ;
}


void CXMethod::calculate_simple(CFunc * f, double a, double b, double &XMin, double &YMin)
{
	double realepsilon;
	int realsteps;
	list<CMyPoint> Labels;
	calculate(f, a, b, 10, 0.0, 1.0, 2.0, true, realepsilon, realsteps, XMin, YMin, Labels);
}

CXMethod::CXMethod(void):m_f(0), m_m(1.0),m_max_tg(0.0){}
CXMethod::~CXMethod(void){}
